#!/bin/bash

# numeric Deploy API服务动态启动脚本 (CPU版本)
# 用法: ./start_service.sh --model <path> [--port <port>] [--ssh-port <port>]

set -e  # 遇到错误立即退出

# 默认值
MODEL_PATH=""
APP_PORT=5090
SSH_PORT=22
HOST_SSH_PORT=""

# 解析命令行参数
while [[ $# -gt 0 ]]; do
    case $1 in
        --model)
            MODEL_PATH="$2"
            shift 2
            ;;
        --port)
            APP_PORT="$2"
            shift 2
            ;;
        --ssh-port)
            HOST_SSH_PORT="$2"
            shift 2
            ;;
        --help|-h)
            echo "🚀 numeric Deploy API服务启动脚本"
            echo ""
            echo "用法: $0 [--model <path>] [--port <port>] [--ssh-port <port>]"
            echo ""
            echo "参数说明:"
            echo "  --model <path>      - 模型路径（必须，可以是目录路径或文件路径）"
            echo "                       目录路径: 包含model.joblib的目录"
            echo "                       文件路径: model.joblib文件的完整路径"
            echo "  --port <port>       - 应用服务端口号（可选，默认5090）"
            echo "  --ssh-port <port>   - 主机SSH映射端口（可选，默认自动计算）"
            echo "  --help, -h          - 显示帮助信息"
            echo ""
            echo "注意:"
            echo "  - 模型路径可以是绝对路径或相对路径"
            echo "  - 可以传入目录路径（如: /path/to/save_model）"
            echo "  - 也可以传入文件路径（如: /path/to/save_model/model.joblib）"
            echo "  - 模型目录必须包含 model.joblib 文件"
            echo "  - SSH端口会自动计算（4022 + 应用端口 - 5090），或使用 --ssh-port 指定"
            echo ""
            echo "示例:"
            echo "  # 使用目录路径，默认端口5090"
            echo "  $0 --model /path/to/save_model"
            echo ""
            echo "  # 使用文件路径，指定端口"
            echo "  $0 --model /path/to/save_model/model.joblib --port 5091"
            echo ""
            echo "  # 使用相对路径"
            echo "  $0 --model ../save_model/model.joblib --port 8775"
            echo ""
            echo "  # 指定应用端口和SSH端口"
            echo "  $0 --model /path/to/save_model --port 5091 --ssh-port 1202"
            exit 0
            ;;
        *)
            echo "❌ 未知参数: $1"
            echo "使用 --help 查看帮助信息"
            exit 1
            ;;
    esac
done

# 检查必需参数
if [ -z "$MODEL_PATH" ]; then
    echo "❌ 错误: 必须指定模型路径"
    echo "使用 --model 指定模型路径，或使用 --help 查看帮助信息"
    exit 1
fi

# 处理模型路径：如果传入的是文件路径，提取目录部分
if [ -f "$MODEL_PATH" ]; then
    # 传入的是文件路径，提取目录部分
    MODEL_DIR="$(dirname "$MODEL_PATH")"
    MODEL_FILE="$(basename "$MODEL_PATH")"
    echo "ℹ️  检测到文件路径，使用目录: $MODEL_DIR"
    # 如果文件名不是 model.joblib，给出提示
    if [ "$MODEL_FILE" != "model.joblib" ]; then
        echo "⚠️  警告: 文件名不是 model.joblib，而是 $MODEL_FILE"
        echo "容器内将查找 model.joblib 文件"
    fi
    MODEL_PATH="$MODEL_DIR"
elif [ -d "$MODEL_PATH" ]; then
    # 传入的是目录路径，直接使用
    MODEL_DIR="$MODEL_PATH"
else
    echo "❌ 错误: 模型路径不存在: $MODEL_PATH"
    echo "请确保路径正确（可以是目录路径或文件路径）"
    exit 1
fi

# 检查模型目录是否存在
if [ ! -d "$MODEL_DIR" ]; then
    echo "❌ 错误: 模型目录不存在: $MODEL_DIR"
    exit 1
fi

# 检查模型文件是否存在
if [ ! -f "$MODEL_DIR/model.joblib" ]; then
    echo "⚠️  警告: 模型文件不存在: $MODEL_DIR/model.joblib"
    echo "请确保模型文件存在，否则服务可能无法正常启动"
    read -p "是否继续? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "❌ 取消启动"
        exit 1
    fi
fi

# 验证端口号是否为数字
if ! [[ "$APP_PORT" =~ ^[0-9]+$ ]]; then
    echo "❌ 错误: 应用端口必须是数字: $APP_PORT"
    exit 1
fi

# 自动计算SSH端口（如果未指定）
if [ -z "$HOST_SSH_PORT" ]; then
    HOST_SSH_PORT=$((4022 + APP_PORT - 5090))
fi

# 应用端口和主机端口使用相同的值

# 验证SSH端口号
if ! [[ "$HOST_SSH_PORT" =~ ^[0-9]+$ ]]; then
    echo "❌ 错误: SSH端口必须是数字: $HOST_SSH_PORT"
    exit 1
fi

# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATE_FILE="$SCRIPT_DIR/docker-compose.numeric.cpu.template.yml"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.numeric.cpu.${APP_PORT}.yml"
CONTAINER_NAME="numeric-deploy-${APP_PORT}"
IMAGE_NAME="devdeploy-numeric-api-cpu:latest"

# 处理模型路径：转换为绝对路径（使用处理后的目录路径）
if [[ "$MODEL_DIR" == /* ]]; then
    # 已经是绝对路径，直接使用
    VOLUME_PATH="$MODEL_DIR"
else
    # 相对路径，转换为绝对路径
    VOLUME_PATH="$(cd "$MODEL_DIR" && pwd)"
fi

echo "🚀 启动numeric Deploy API服务 (CPU版本)..."
echo ""
echo "📋 配置信息:"
echo "  - 模型目录: ${MODEL_DIR}"
echo "  - 模型挂载路径: ${VOLUME_PATH}"
echo "  - 端口: ${APP_PORT}"
echo "  - SSH端口: ${SSH_PORT} (主机: ${HOST_SSH_PORT})"
echo "  - 容器名称: ${CONTAINER_NAME}"
echo "  - Compose文件: ${COMPOSE_FILE}"
echo ""

# 检查Docker是否运行
if ! docker info > /dev/null 2>&1; then
    echo "❌ Docker未运行，请先启动Docker服务"
    exit 1
fi

# 检查端口是否被占用
check_port() {
    local port=$1
    local port_name=$2
    if command -v netstat > /dev/null 2>&1; then
        if netstat -tuln 2>/dev/null | grep -q ":${port}"; then
            echo "❌ 端口 ${port} (${port_name}) 已被占用"
            echo "请使用其他端口"
            exit 1
        fi
    elif command -v lsof > /dev/null 2>&1; then
        if lsof -i :${port} > /dev/null 2>&1; then
            echo "❌ 端口 ${port} (${port_name}) 已被占用"
            echo "请使用其他端口"
            exit 1
        fi
    fi
}

check_port "$APP_PORT" "应用端口"
check_port "$HOST_SSH_PORT" "SSH端口"

# 检查容器是否已存在
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
    echo "⚠️  容器 ${CONTAINER_NAME} 已存在"
    read -p "是否要停止并删除旧容器? (y/N): " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        echo "正在停止旧容器..."
        docker-compose -f ${COMPOSE_FILE} down 2>/dev/null || true
        docker stop ${CONTAINER_NAME} > /dev/null 2>&1 || true
        docker rm ${CONTAINER_NAME} > /dev/null 2>&1 || true
    else
        echo "❌ 取消启动"
        exit 1
    fi
fi

# 检查模板文件是否存在
if [ ! -f "$TEMPLATE_FILE" ]; then
    echo "❌ 模板文件不存在: $TEMPLATE_FILE"
    echo "请确保模板文件在正确位置"
    exit 1
fi

echo "📝 生成 docker-compose 配置文件: ${COMPOSE_FILE}..."

# 使用 sed 替换模板中的占位符
sed -e "s|{{IMAGE_NAME}}|${IMAGE_NAME}|g" \
    -e "s|{{CONTAINER_NAME}}|${CONTAINER_NAME}|g" \
    -e "s|{{PORT}}|${APP_PORT}|g" \
    -e "s|{{SSH_HOST_PORT}}|${HOST_SSH_PORT}|g" \
    -e "s|{{MODEL_PATH}}|${VOLUME_PATH}|g" \
    "${TEMPLATE_FILE}" > "${COMPOSE_FILE}"

echo "✅ 配置文件已生成"

# 检查Docker镜像是否存在，如果不存在则构建
if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${IMAGE_NAME}$"; then
    echo "🔨 构建Docker镜像: ${IMAGE_NAME}..."
    cd "$SCRIPT_DIR"
    docker-compose -f ${COMPOSE_FILE} build
    
    if [ $? -ne 0 ]; then
        echo "❌ 镜像构建失败"
        rm -f ${COMPOSE_FILE}
        exit 1
    fi
    
    echo "✅ 镜像构建完成"
else
    echo "✅ 镜像已存在: ${IMAGE_NAME}"
    echo "如需重新构建，请先删除镜像: docker rmi ${IMAGE_NAME}"
fi

# 启动服务
echo "🚀 启动服务..."
cd "$SCRIPT_DIR"
docker-compose -f ${COMPOSE_FILE} up -d

if [ $? -ne 0 ]; then
    echo "❌ 服务启动失败"
    echo "查看日志: docker-compose -f ${COMPOSE_FILE} logs"
    exit 1
fi

# 等待服务启动
echo "⏳ 等待服务启动..."
sleep 5

# 检查服务状态
if docker ps | grep -q "${CONTAINER_NAME}"; then
    echo "✅ 服务启动成功！"
    echo ""
    echo "📋 服务信息："
    echo "  - 容器名称: ${CONTAINER_NAME}"
    echo "  - API地址: http://localhost:${APP_PORT}"
    echo "  - 预测接口: http://localhost:${APP_PORT}/predict"
    echo "  - SSH访问: ssh root@localhost -p ${HOST_SSH_PORT} (密码: 123)"
    echo ""
    echo "🔍 常用命令:"
    echo "  - 查看日志: docker-compose -f ${COMPOSE_FILE} logs -f"
    echo "  - 查看状态: docker-compose -f ${COMPOSE_FILE} ps"
    echo "  - 停止服务: docker-compose -f ${COMPOSE_FILE} down"
    echo "  - 重启服务: docker-compose -f ${COMPOSE_FILE} restart"
    echo ""
    echo "🧪 测试API:"
    echo "  curl -X POST http://localhost:${APP_PORT}/predict \\"
    echo "    -H \"Content-Type: application/json\" \\"
    echo "    -d '{\"feature_0\": 1.0, \"feature_1\": 2.0, \"feature_2\": 3.0, \"feature_3\": 4.0, \"feature_4\": 5.0}'"
else
    echo "❌ 服务启动失败"
    echo "查看日志: docker-compose -f ${COMPOSE_FILE} logs"
    exit 1
fi
